module ahb_sub_system(
    input               HCLK,
    input               HRESETn,

    input        [31:0] HADDR,
    input         [1:0] HTRANS,
    input         [2:0] HSIZE,
    input         [3:0] HPROT,
    input               HWRITE,
    input               HREADY,
    input        [31:0] HWDATA,
    output wire         HREADYOUT,
    output wire  [31:0] HRDATA,
    output wire         HRESP,

    input  wire         RXD,
    output wire         TXD,
    output wire         TXEN,
    // UART signal
    output wire         TXINT,      // Transmit Interrupt
    output wire         RXINT,      // Receive Interrupt
    output wire         TXOVRINT,   // Transmit overrun Interrupt
    output wire         RXOVRINT,   // Receive overrun Interrupt
    output wire         UARTINT,    // Combined interrupt
    // GPIO signal
    input  wire  [15:0] GPIOIN,     // GPIO input
    output wire  [15:0] GPIOOUT,    // GPIO output
    output wire  [15:0] GPIOEN,     // GPIO output enable
    output wire  [15:0] GPIOINT,    // Interrupt output for each pin
    output wire         COMBINT,    // Combined interrupt
    // I2C signal
    input  wire         SDAIN,
    output wire         SCL,
    output wire         SDAOUTEN_n,
    // Timer signal
    output wire         TIMERINT    // Timer interrupt
);

//---------------------------------------------------------
//AHB slave connection
//---------------------------------------------------------

wire    HSEL0;
wire    HSEL1;
wire    HSEL2;
wire    HSEL3;
wire    HSEL4;
wire    HSEL5;
wire    HSEL6;
wire    HSEL7;
wire    HSEL8;
wire    HSEL9;

ahb_slave_decoder u_ahb_slave_decoder(
    .HADDR_upper (HADDR[31:16]),
    .HSEL0       (HSEL0       ),
    .HSEL1       (HSEL1       ),
    .HSEL2       (HSEL2       ),
    .HSEL3       (HSEL3       ),
    .HSEL4       (HSEL4       ),
    .HSEL5       (HSEL5       ),
    .HSEL6       (HSEL6       ),
    .HSEL7       (HSEL7       ),
    .HSEL8       (HSEL8       ),
    .HSEL9       (HSEL9       )
);

//signal declearation
wire HREADYOUT0;
wire HRESP0;
wire [31:0] HRDATA0;
wire HREADYOUT1;
wire HRESP1;
wire [31:0] HRDATA1;
wire HREADYOUT2;
wire HRESP2;
wire [31:0] HRDATA2;
wire HREADYOUT3;
wire HRESP3;
wire [31:0] HRDATA3;
wire HREADYOUT4;
wire HRESP4;
wire [31:0] HRDATA4;
wire HREADYOUT5;
wire HRESP5;
wire [31:0] HRDATA5;
wire HREADYOUT6;
wire HRESP6;
wire [31:0] HRDATA6;
wire HREADYOUT7;
wire HRESP7;
wire [31:0] HRDATA7;
wire HREADYOUT8;
wire HRESP8;
wire [31:0] HRDATA8;
wire HREADYOUT9;
wire HRESP9;
wire [31:0] HRDATA9 = 32'b0;

cmsdk_ahb_slave_mux 
#(
    .PORT0_ENABLE (1'b1 ),
    .PORT1_ENABLE (1'b1 ),
    .PORT2_ENABLE (1'b1 ),
    .PORT3_ENABLE (1'b0 ),
    .PORT4_ENABLE (1'b0 ),
    .PORT5_ENABLE (1'b0 ),
    .PORT6_ENABLE (1'b0 ),
    .PORT7_ENABLE (1'b0 ),
    .PORT8_ENABLE (1'b0 ),
    .PORT9_ENABLE (1'b1 ),
    .DW           (32   )
)
u_cmsdk_ahb_slave_mux(
    .HCLK       (HCLK       ),
    .HRESETn    (HRESETn    ),
    .HREADY     (HREADY    ),

    .HREADYOUT  (HREADYOUT  ),
    .HRESP      (HRESP      ),
    .HRDATA     (HRDATA     ),
    //slave0 for DTCM @ 0x2000xxxx
    .HSEL0      (HSEL0      ),
    .HREADYOUT0 (HREADYOUT0 ),
    .HRESP0     (HRESP0     ),
    .HRDATA0    (HRDATA0    ),
    //slave1 for apb subsystem @ 0x4000xxxx
    .HSEL1      (HSEL1      ),
    .HREADYOUT1 (HREADYOUT1 ),
    .HRESP1     (HRESP1     ),
    .HRDATA1    (HRDATA1    ),
    //slave2 for ahb GPIO @ 0x4001xxxx
    .HSEL2      (HSEL2      ),
    .HREADYOUT2 (HREADYOUT2 ),
    .HRESP2     (HRESP2     ),
    .HRDATA2    (HRDATA2    ),
    //slave9 for default slave @ others
    .HSEL9      (HSEL9      ),
    .HREADYOUT9 (HREADYOUT9 ),
    .HRESP9     (HRESP9     ),
    .HRDATA9    (HRDATA9    ),

    .HSEL3      (HSEL3      ),
    .HREADYOUT3 (HREADYOUT3 ),
    .HRESP3     (HRESP3     ),
    .HRDATA3    (HRDATA3    ),
    .HSEL4      (HSEL4      ),
    .HREADYOUT4 (HREADYOUT4 ),
    .HRESP4     (HRESP4     ),
    .HRDATA4    (HRDATA4    ),
    .HSEL5      (HSEL5      ),
    .HREADYOUT5 (HREADYOUT5 ),
    .HRESP5     (HRESP5     ),
    .HRDATA5    (HRDATA5    ),
    .HSEL6      (HSEL6      ),
    .HREADYOUT6 (HREADYOUT6 ),
    .HRESP6     (HRESP6     ),
    .HRDATA6    (HRDATA6    ),
    .HSEL7      (HSEL7      ),
    .HREADYOUT7 (HREADYOUT7 ),
    .HRESP7     (HRESP7     ),
    .HRDATA7    (HRDATA7    ),
    .HSEL8      (HSEL8      ),
    .HREADYOUT8 (HREADYOUT8 ),
    .HRESP8     (HRESP8     ),
    .HRDATA8    (HRDATA8    )
);

//---------------------------------------------------------
//SRAM-DTCM
//---------------------------------------------------------

wire [31:0] SRAMRDATA;
wire [13:0] SRAMADDR;
wire  [3:0] SRAMWREN;
wire [31:0] SRAMWDATA;
wire        SRAMCS;

cmsdk_ahb_to_sram 
#(
    .AW (16 )
)
u_ahb_to_DTCM(
    .HCLK      (HCLK      ),
    .HRESETn   (HRESETn   ),

    .HSEL      (HSEL0     ),
    .HREADY    (HREADYOUT ),
    .HTRANS    (HTRANS    ),
    .HSIZE     (HSIZE     ),
    .HWRITE    (HWRITE    ),
    .HADDR     (HADDR     ),
    .HWDATA    (HWDATA    ),
    .HREADYOUT (HREADYOUT0),
    .HRESP     (HRESP0    ),
    .HRDATA    (HRDATA0   ),

    .SRAMRDATA (SRAMRDATA ),
    .SRAMADDR  (SRAMADDR  ),
    .SRAMWEN   (SRAMWREN  ),
    .SRAMWDATA (SRAMWDATA ),
    .SRAMCS    (SRAMCS    )
);

cmsdk_fpga_sram 
#(
    .AW        (14        )
)
u_DTCM(
    .CLK       (HCLK      ),
    .ADDR      (SRAMADDR  ),
    .WDATA     (SRAMWDATA ),
    .WREN      (SRAMWREN  ),
    .CS        (SRAMCS    ),
    .RDATA     (SRAMRDATA )
);

//---------------------------------------------------------
//APB subsystem
//---------------------------------------------------------

apb_subsystem_top 
#(
    .ADDRWIDTH (16 )
)
u_apb_subsystem(
    .HCLK      (HCLK      ),
    .HRESETn   (HRESETn   ),

    .HSEL      (HSEL1     ),
    .HADDR     (HADDR     ),
    .HTRANS    (HTRANS    ),
    .HSIZE     (HSIZE     ),
    .HPROT     (HPROT     ),
    .HWRITE    (HWRITE    ),
    .HREADY    (HREADYOUT ),
    .HWDATA    (HWDATA    ),
    .HREADYOUT (HREADYOUT1),
    .HRDATA    (HRDATA1   ),
    .HRESP     (HRESP1    ),
    
    .PCLK      (HCLK      ),
    .PCLKG     (HCLK      ),//gated colck for power consumption
    .PCLKEN    (1'b1      ),//If PCLK is same as HCLK, set PCLKEN to 1
    .PRESETn   (HRESETn   ),
//    .APBACTIVE (APBACTIVE ), for PCLK gateing

    .RXD       (RXD       ),
    .TXD       (TXD       ),
    .TXEN      (TXEN      ),
    .TXINT     (TXINT     ),
    .RXINT     (RXINT     ),
    .TXOVRINT  (TXOVRINT  ),
    .RXOVRINT  (RXOVRINT  ),
    .UARTINT   (UARTINT   ),
    .TIMERINT  (TIMERINT  ),
    .SDA       (SDAIN     ),
    .SCL       (SCL       ),
    .SDAOUTEN_n(SDAOUTEN_n)
);

//---------------------------------------------------------
//APB GPIO
//---------------------------------------------------------

wire [15:0] PORTFUNC;
cmsdk_ahb_gpio 
#(
    .ALTERNATE_FUNC_MASK    (16'h0000    ),
    .ALTERNATE_FUNC_DEFAULT (16'h0000    ),
    .BE                     (0           )
)
u_cmsdk_ahb_gpio(
    .HCLK      (HCLK      ),
    .HRESETn   (HRESETn   ),
    .FCLK      (HCLK      ),
    .HSEL      (HSEL2     ),
    .HREADY    (HREADYOUT ),
    .HTRANS    (HTRANS    ),
    .HSIZE     (HSIZE     ),
    .HWRITE    (HWRITE    ),
    .HADDR     (HADDR     ),
    .HWDATA    (HWDATA    ),
    .ECOREVNUM (4'b0      ),

    .HREADYOUT (HREADYOUT2),
    .HRESP     (HRESP2    ),
    .HRDATA    (HRDATA2   ),
    //connected to tri-state buffer
    .PORTIN    (GPIOIN    ),//GPIO input
    .PORTOUT   (GPIOOUT   ),//GPIO output
    .PORTEN    (GPIOEN    ),//GPIO output en
    .PORTFUNC  (PORTFUNC  ),//determin GPIO or alternate function NA
    //interrupt signal to NVIC
    .GPIOINT   (GPIOINT   ),
    .COMBINT   (COMBINT   )
);


//---------------------------------------------------------
//Default slave
//---------------------------------------------------------

cmsdk_ahb_default_slave u_default_slave(
    .HCLK      (HCLK      ),
    .HRESETn   (HRESETn   ),
    .HSEL      (HSEL9     ),
    .HTRANS    (HTRANS    ),
    .HREADY    (HREADYOUT ),
    .HREADYOUT (HREADYOUT9),
    .HRESP     (HRESP9    )
);


endmodule